<?php
/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */

defined('IN_COMPONENT_CONTROLLER') or die();

function address_label(&$address)
{
	$addressString = $address['name'] . "\n";
	if (returnBoolean(ACCOUNT_COMPANY)) $addressString .= $address['company'] . "\n";
	$addressString .= $address['street_address'] . "\n";
	if (returnBoolean(ACCOUNT_SUBURB)) $addressString .= $address['suburb'] . "\n";
	$addressString .= $address['city'];
	if (returnBoolean(ACCOUNT_STATE)) $addressString .= ", " . $address['state'];
	$addressString .= " " . $address['postcode'] . "\n";
	$addressString .= $address['country'] . "\n";

	return $addressString;
}

class CheckoutComponent
{
	function CheckoutComponent()
	{
		$this->cart_prices = array();
	}

	function action(&$params, $action)
	{
		$this->setup($params);
		return $this->query($params);
	}

	/**
	 * make sure appropriate shipto, billto information is setup *
	 */
	function setup(&$params) 
	{
		$this->errorCode = 0;
		$this->errorMessage = '';
		$this->paymentErrorMessage = '';
		$accountId = (int)$params['accountId'];
		$basketAccountId = (int)$params['basketAccountId'];

		//Cart Exists in Database.
		if (($accountId == 0 && $basketAccountId < 0) || $accountId > 0 && $basketAccountId == $accountId)
		{
			$display_state = returnBoolean(ACCOUNT_STATE);
			$entry_postcode_length_min = (int)ENTRY_POSTCODE_MIN_LENGTH;
			$entry_state_length_min = (int)ENTRY_STATE_MIN_LENGTH;

			//TBD: split up by Shipping Locations
			//Ship From
			$shipFromCountryCode = SHIPPING_ORIGIN_COUNTRY;
			$sqlQuery = 'select countries_id, countries_name, countries_iso_code_2, countries_iso_code_3, address_format_id from ' . TABLE_COUNTRIES . ' where countries_id=' . $shipFromCountryCode;
			$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
			$i = 0;
			while($row = mysql_fetch_array($dataReturned))
			{
				$shipFrom['country'] = $row['countries_name'];
				$shipFrom['country_id'] = $row['countries_id'];
				$shipFrom['country_iso_code_2'] = $row['countries_iso_code_2'];
				$shipFrom['country_iso_code_3'] = $row['countries_iso_code_3'];
				$shipFrom['address_format_id'] = $row['address_format_id'];
			}
			$shipFrom['zone_id'] = STORE_ZONE;
			$shipFrom['postcode'] = SHIPPING_ORIGIN_ZIP;

       			if ($shipFrom['country_iso_code_2'] == 'US' && $shipFrom['postcode'] != null && strlen($shipFrom['postcode']) > 4) $shipFrom['postcode'] = substr($shipFrom['postcode'], 0, 5);


			if ($accountId > 0)
			{
				$sqlQuery = 'select customers_firstname, customers_lastname, customers_email_address, ' .
				'customers_telephone, customers_isWholesale, customers_isLogin, customers_default_address_id ' .
				'from ' . TABLE_CUSTOMERS . ' where customers_id=\'' . $accountId . '\'';
				$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
				$i = 0;
				while($row = mysql_fetch_array($dataReturned))
				{
					$default_addressId = (int)$row['customers_default_address_id'];
					$email_address = $row['customers_email_address'];
					$account_name = $row['customers_firstname'] . " " . $row['customers_lastname'];
					$telephone = $row['customers_telephone'];
					$wholesale = (int)$row['customers_isWholesale'];
					$isLogin = (int)$row['customers_isLogin'];
					
				}
				$addresses = getAddresses($accountId, $default_addressId);

				$shipToAddressId = (int)$params['shipToAddressId'];
				$billToAddressId = (int)$params['billToAddressId'];
				reset($addresses);
				while (list(,$address) = each($addresses))
				{
					if ($shipToAddressId == $address['id']) $shipTo = $address;
					if ($billToAddressId == $address['id']) $billTo = $address;
					if ($default_addressId == $address['id']) $accountInfo = $address;
				}
				if ($shipToAddressId == 0) $shipTo = $accountInfo;
				if ($billToAddressId == 0) $billTo = $accountInfo;

				$accountInfo['email_address'] = $email_address;
				$accountInfo['name'] = $account_name;
				$accountInfo['telephone'] = $telephone;
				if ($wholesale == 0) $accountInfo['wholesale'] = false;
				else $accountInfo['wholesale'] = true;

				if ($isLogin == 0) $accountInfo['isLogin'] = false;
				else $accountInfo['isLogin'] = true;

				$this->accountInfo = $accountInfo;
			}
			//Ship To (from request).
			if ($shipTo == null)
			{
				//Guest
				$shipToPostcode = prepare_input($params['shipToPostcode']);
				$shipToCountryName = prepare_input($params['shipToCountry']);
				$shipToState = prepare_input($params['shipToState']);

				if (strlen($shipToPostcode) < $entry_postcode_length_min) {
					$this->errorCode = -10;
					$this->errorMessage = 'shipToPostcodeTooShort';
					return;
				}
				if ($display_state && strlen($shipToState) < $entry_state_length_min) {
					$this->errorCode = -20;
					$this->errorMessage = 'shipToStateTooShort';
					return;
				}


				if ($shipToCountryName != null && strlen($shipToCountryName) > 0)
				{
					$sqlQuery = 'select countries_id, countries_name, countries_iso_code_2, countries_iso_code_3, address_format_id from ' . TABLE_COUNTRIES . ' where countries_name=\'' . $shipToCountryName . '\'';
					$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
					$i = 0;
					while($row = mysql_fetch_array($dataReturned))
					{
						$shipToCountryId = $row['countries_id'];
						$shipToCountryName = $row['countries_name'];
						$shipToCountry_iso_code_2 = $row['countries_iso_code_2'];
						$shipToCountry_iso_code_3 = $row['countries_iso_code_3'];
						$shipToAddressFormatId = $row['address_format_id'];
					}
	
        				if ($shipToCountry_iso_code_2 == 'US' && $shipToPostcode != null && strlen($shipToPostcode) > 4) $shipToPostcode = substr($shipToPostcode, 0, 5);
	
					//confirm Ship To State	
					if ($shipToCountry_iso_code_2 == 'US' && strlen($shipToPostcode) == 5)
					{
						include_once('includes/modules/shipping/usps.php');
						$obj = new usps;
						if ($obj != null && $obj->addr_info_enabled)
						{
							$subParams['Postcode'] = $shipToPostcode;
							$cityState = $obj->cityStateLookup($subParams);
							$state = $cityState['state'];
							if ($state != null) $shipToState = $state;
							else
							{
								$error = $cityState['error'];
								var_dump($error);
							}
						}
					}

					//Add zone_id (state)
					$zone_id = 0;
					if ($display_state && strlen($shipToState) > 0)
					{
						$sqlQuery = 'select zone_id from ' . TABLE_ZONES . ' ' .
						'where zone_country_id = ' . $shipToCountryId . ' and zone_code = \'' . mysql_real_escape_string($shipToState) . '\'';
	
						$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
						while($row = mysql_fetch_array($dataReturned))
						{
							$zone_id = $row['zone_id'];
						}
					}
				}

				$shipTo['postcode'] = $shipToPostcode;
				$shipTo['zone_id'] = $zone_id;
				$shipTo['state'] = $state;
				$shipTo['country'] = $shipToCountryName;
				$shipTo['country_id'] = $shipToCountryId;
				$shipTo['country_iso_code_2'] = $shipToCountry_iso_code_2;
				$shipTo['country_iso_code_3'] = $shipToCountry_iso_code_3;
				$shipTo['address_format_id'] = 	$shipToAddressFormatId;
			}

			//Bill To (from request).
			if ($billTo == null)
			{
				//Guest
				$billToPostcode = prepare_input($params['billToPostcode']);
				$billToCountryName = prepare_input($params['billToCountry']);
				$billToState = prepare_input($params['billToState']);

				if (strlen($billToPostcode) < $entry_postcode_length_min) {
					$this->errorCode = -30;
					$this->errorMessage = 'billToPostcodeTooShort';
					return;
				}
				if ($display_state && strlen($billToState) < $entry_state_length_min) {
					$this->errorCode = -40;
					$this->errorMessage = 'billToStateTooShort';
					return;
				}


				if ($billToCountryName != null && strlen($billToCountryName) > 0)
				{
					$sqlQuery = 'select countries_id, countries_name, countries_iso_code_2, countries_iso_code_3, address_format_id from ' . TABLE_COUNTRIES . ' where countries_name=\'' . $billToCountryName . '\'';
					$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
					$i = 0;
					while($row = mysql_fetch_array($dataReturned))
					{
						$billToCountryId = $row['countries_id'];
						$billToCountryName = $row['countries_name'];
						$billToCountry_iso_code_2 = $row['countries_iso_code_2'];
						$billToCountry_iso_code_3 = $row['countries_iso_code_3'];
						$billToAddressFormatId = $row['address_format_id'];
					}
	
        				if ($billToCountry_iso_code_2 == 'US' && $billToPostcode != null && strlen($billToPostcode) > 4) $billToPostcode = substr($billToPostcode, 0, 5);
	
					//confirm Ship To State	
					if ($billToCountry_iso_code_2 == 'US' && strlen($billToPostcode) == 5)
					{
						include_once('includes/modules/shipping/usps.php');
						$obj = new usps;
						if ($obj != null && $obj->addr_info_enabled)
						{
							$subParams['Postcode'] = $billToPostcode;
							$cityState = $obj->cityStateLookup($subParams);
							$state = $cityState['state'];
							if ($state != null) $billToState = $state;
							else
							{
								$error = $cityState['error'];
								var_dump($error);
							}
						}
					}

					//Add zone_id (state)
					$zone_id = 0;
					if ($display_state && strlen($billToState) > 0)
					{
						$sqlQuery = 'select zone_id from ' . TABLE_ZONES . ' ' .
						'where zone_country_id = ' . $billToCountryId . ' and zone_code = \'' . mysql_real_escape_string($billToState) . '\'';
	
						$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
						while($row = mysql_fetch_array($dataReturned))
						{
							$zone_id = $row['zone_id'];
						}
					}
				}

				$billTo['postcode'] = $billToPostcode;
				$billTo['zone_id'] = $zone_id;
				$billTo['state'] = $state;
				$billTo['country'] = $billToCountryName;
				$billTo['country_id'] = $billToCountryId;
				$billTo['country_iso_code_2'] = $billToCountry_iso_code_2;
				$billTo['country_iso_code_3'] = $billToCountry_iso_code_3;
				$billTo['address_format_id'] = 	$billToAddressFormatId;
			}
			//taxes
			if ($shipTo['country'] != null && strlen($shipTo['country']) > 0)
			{
				$this->tax_country_id = (int)$shipTo['country_id'];
				$this->tax_zone_id = (int)$shipTo['zone_id'];
			}
			else if ($billTo['country'] != null && strlen($billTo['country']) > 0)
			{
				$this->tax_country_id = (int)$billTo['country_id'];
				$this->tax_zone_id = (int)$billTo['zone_id'];
			}
			else
			{
				$this->tax_country_id = 0;
				$this->tax_zone_id = 0;
			}

			//Collect Cart Information 
			$subParams['handle'] = 'Cart';
			$subParams['accountId'] = $basketAccountId;
			$subParams['languageId'] = (int)$params['languageId'];
			$subParams['max_rows'] = MAX_QTY_IN_CART;
			$subParams['searchCart'] = true;

			require_once('includes/components/ProductsSearchSubComponent.php');
			$subComponent = new ProductsSearchSubComponent();
			$return = $subComponent->query($subParams);
			if ($return != null)
			{
				$this->cart = $return['Cart'];
			}

			$this->shipFrom = $shipFrom;
			$this->shipTo = $shipTo;
			$this->billTo = $billTo;
		}
		else
		{
			//missing cart
			$this->errorCode = -5;
			$this->errorMessage = 'cartMissing';
		}
		return $params;
	}

	function query(&$params) 
	{
		$value{'CheckoutComponentMetaData'}{'cc_number_length_min'}=(int)CC_NUMBER_MIN_LENGTH;
		$value{'CheckoutComponentMetaData'}{'cc_owner_length_min'}=(int)CC_OWNER_MIN_LENGTH;

		$return = $this->generateShipping($params);

		if ($this->errorCode != 0) return;

		$value{'CheckoutComponent'}{0}{'shipping'} = $return{'CheckoutComponent'}{0}{'shipping'};
		$value{'CheckoutComponent'}{0}{'shipping_module'} = $this->shipping_module;
		$value{'CheckoutComponent'}{0}{'shipping_service'} = $this->shipping_service;
		$value{'CheckoutComponent'}{0}{'shipping_use_cheapest'} = returnBoolean(MODULE_SHIPPING_USE_CHEAPEST);

		$return = $this->order_total($params);

		if ($this->errorCode != 0) return;

		$value{'CheckoutComponent'}{0}{'totals'} = $return{'CheckoutComponent'}{0}{'totals'};

		$return = $this->payment($params);
		$value{'CheckoutComponent'}{0}{'payment'} = $return{'CheckoutComponent'}{0}{'payment'};

		$value{'CheckoutComponent'}{0}{'error_code'} = $this->errorCode;
		$value{'CheckoutComponent'}{0}{'error_message'} = $this->errorMessage;
		$value{'CheckoutComponent'}{0}{'payment_error_message'} = $this->paymentErrorMessage;

		if ($this->errorCode == 0)
		{
			//To make sure there are no misunderstandings, send back the action just completed.
			$action = prepare_input($params['action']);
			$value{'CheckoutComponent'}{0}{'action_completed'}= $action;
		}

		return $value;
	}

	function generateShipping(&$params) 
	{
		$action = prepare_input($params['action']);
		//Load shipping modules
		if (defined('MODULE_SHIPPING_INSTALLED') && MODULE_SHIPPING_INSTALLED != null)
		{
			//Get Cart Weight
			$cart_weight = 0.0;
			$sz = sizeof($this->cart);
			for ($i=0; $i< $sz; $i++)
			{
				$weight = (double)$this->cart[$i]['weight'];
				$cart_weight += ($weight * (int)$this->cart[$i]['cart_qty']);
			}
			$shipping_weight = $cart_weight;

			//Add box weight.
			if (SHIPPING_BOX_WEIGHT >= $shipping_weight*SHIPPING_BOX_PADDING/100) {
				$shipping_weight = $shipping_weight+SHIPPING_BOX_WEIGHT;
			} 
			else {
				$shipping_weight = $shipping_weight + ($shipping_weight*SHIPPING_BOX_PADDING/100);
			}
			$shipping_num_boxes = 1;
			if ($shipping_weight > SHIPPING_MAX_WEIGHT) {
				// Split into many boxes
				$shipping_num_boxes = ceil($shipping_weight/SHIPPING_MAX_WEIGHT);
				$shipping_weight = $shipping_weight/$shipping_num_boxes;
			}
			$shipping_module = prepare_input($params['shipping_module']);
			$shipping_service = prepare_input($params['shipping_service']);
			if ($shipping_module != null && $shipping_module == 'free')
			{
				$shipping_module = null;
				$shipping_service = null;
			}
			$selectedShipping = false;
			if ($shipping_service != null && $shipping_service != '') $selectedShipping = true;

			$subParams['shipping_weight'] = $shipping_weight;
			$subParams['shipping_num_boxes'] = $shipping_num_boxes;	

			if ($cart_weight == 0)
			{
				$rvalue{'Shipping'}{0}{'weight'}= 0.0;
				$rvalue{'Shipping'}{0}{'num_boxes'}= 0.0;
				$rvalue{'Shipping'}{0}{'module'}= 'free';
				$rvalue{'Shipping'}{0}{'tax_rate'}= 0.0;
				$rvalue{'Shipping'}{0}{'handling'}= 0.0;
				$rvalue{'Shipping'}{0}{'rates'}{0}{'service'}= 'free';
				$rvalue{'Shipping'}{0}{'rates'}{0}{'postage'}= 0.0;
				$shipping_service = 'free';
				$shipping_module = 'free';
			}
			else if ($action == 'ProcessPayment' && $shipping_module != null && strlen($shipping_module) > 0)
			{
				$subParams['shipping_service'] = $shipping_service;
				include_once('includes/modules/shipping/' . $shipping_module . '.php');
				$class = $shipping_module;
				$obj = new $class;
				if ($obj->enabled)
				{
					$rates = $obj->quote($subParams, $this);
					if ($rates['rates'] != null)
					{
						$tax_class = (int)$rates['tax_class'];
						$tax_rate = get_tax_rate($tax_class, $this->tax_country_id, $this->tax_zone_id);
						$rvalue{'Shipping'}{0}{'weight'}= (double)$shipping_weight;
						$rvalue{'Shipping'}{0}{'num_boxes'}= (int)$shipping_num_boxes;
						$rvalue{'Shipping'}{0}{'module'}= $shipping_module;
						$rvalue{'Shipping'}{0}{'tax_rate'}= $tax_rate;
						$rvalue{'Shipping'}{0}{'handling'}= (double)$rates['handling'];
						$rvalue{'Shipping'}{0}{'rates'}= $rates['rates'];
					}
				}
			}
			else
			{
				$modules = explode(';', MODULE_SHIPPING_INSTALLED);
				reset($modules);
				$i = 0;
				$j = 0;	
				$lowestShippingPrice = 100000.00;
				while (list(, $value) = each($modules)) 
				{
					include_once('includes/modules/shipping/' . $value);
					$class = substr($value, 0, strrpos($value, '.'));
					$obj = new $class;
					if ($obj != null && $obj->enabled)
					{
						$rates = $obj->quote($subParams, $this);
						if ($rates['rates'] != null)
						{
							$tax_class = (int)$rates['tax_class'];
							$tax_rate = get_tax_rate($tax_class, $this->tax_country_id, $this->tax_zone_id);
							$rvalue{'Shipping'}{$j}{'weight'}= (double)$shipping_weight;
							$rvalue{'Shipping'}{$j}{'num_boxes'}= (int)$shipping_num_boxes;
							$rvalue{'Shipping'}{$j}{'module'}= $class;
							$rvalue{'Shipping'}{$j}{'tax_rate'}= $tax_rate;
							$rvalue{'Shipping'}{$j}{'handling'}= (double)$rates['handling'];
							$ratesArray = $rates['rates'];
							$rvalue{'Shipping'}{$j}{'rates'}= $ratesArray;
							if (!$selectedShipping)
							{
								reset($ratesArray);
								while (list($rateKey, $rateArray) = each($ratesArray))
								{
									$shippingPrice = $rateArray['postage'] + $rvalue{'Shipping'}{$j}{'handling'};
									if ($shippingPrice < $lowestShippingPrice)
									{
										$lowestShippingPrice = $shippingPrice;
										$shipping_module = $class;
										$shipping_service = $rateArray['service'];
									}
								}
							}
							$j++;
						}
						$i++;
					}
				}
			}
		}

		$this->shipping = $rvalue['Shipping'];
		$this->shipping_module = $shipping_module;
		$this->shipping_service = $shipping_service;

		$covalue{'CheckoutComponent'}{0}{'shipping'}=$rvalue['Shipping'];
		
		return $covalue;
	}

	function order_total(&$params) 
	{
		//Load order_total modules
		if (defined('MODULE_ORDER_TOTAL_INSTALLED') && MODULE_ORDER_TOTAL_INSTALLED != null)
		{
			$subParams['coupon_code'] = prepare_input($params['coupon_code']);
			$subParams['accountId'] = (int)$params['accountId'];

			$modules = explode(';', MODULE_ORDER_TOTAL_INSTALLED);
			reset($modules);
			$i = 0;					
			while (list(, $value) = each($modules)) 
			{
				include_once('includes/modules/order_total/' . $value);
				$class = substr($value, 0, strrpos($value, '.'));
				$obj = new $class;
				if ($obj != null && $obj->enabled)
				{
					$obj->process($params, $this);
					$i++;
				}
			}
				
		}

		$i = 0;
		$taxation = false;
		reset($this->cart_prices);
		while (list($key, $value) = each($this->cart_prices)) 
		{
			if ($key == 'ot_tax') {
				$taxation = true;
				continue;
			}
			if ($key == 'ot_total') continue;

			$covalue{'CheckoutComponent'}{0}{'totals'}{$i} = $value;
			$i++;
		}
		if ($taxation) {
			$covalue{'CheckoutComponent'}{0}{'totals'}{$i} = $this->cart_prices['ot_tax'];
			$i++;
		}
		$covalue{'CheckoutComponent'}{0}{'totals'}{$i} = $this->cart_prices['ot_total'];

		return $covalue;
	}

	function payment(&$params) 
	{
		//Load payment modules
		if (defined('MODULE_PAYMENT_INSTALLED') && MODULE_PAYMENT_INSTALLED != null)
		{
			//Check Stock Levels
			if (returnBoolean(STOCK_CHECK))
			{
				$this->outOfStock = Array();
				//Check Stock Levels of Order
				$cart = &$this->cart;
				$sz = sizeof($cart);
				$j=0;
				for ($i=0; $i< $sz; $i++)
				{
					$inventory_qty = (int)$cart[$i]['inventory_qty'];
					$cart_qty = (int)$cart[$i]['cart_qty'];
					if (($inventory_qty - $cart_qty) < 1) {
						//Out of Stock
						$this->outOfStock[$j] = $cart[$i]['products_id'];
						$j++;
					}
				}
				if ($j > 0 && !returnBoolean(STOCK_ALLOW_CHECKOUT))
				{
					$this->errorCode = -200;
					$this->errorMessage = 'OutOfStock';
				}
			}

			//Setup Default Currency
			$sqlQuery = 'select symbol_left, symbol_right, decimal_point, thousands_point, decimal_places, value from ' . TABLE_CURRENCIES . ' where code=\'' . DEFAULT_CURRENCY . '\'';
			$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
			$currency = array();
			while($row = mysql_fetch_array($dataReturned))
			{
				$currency['code'] = DEFAULT_CURRENCY;
				$currency['symbol_left'] = $row['symbol_left'];
				$currency['symbol_right'] = $row['symbol_right'];
				$currency['decimal_point'] = $row['decimal_point'];
				$currency['thousands_point'] = $row['thousands_point'];
				$currency['decimal_places'] = (int)$row['decimal_places'];
				$currency['value'] = (double)$row['value'];
				break;
			}
			$this->currency = &$currency;

			$payment_module = prepare_input($params['payment_module']);
			$action = prepare_input($params['action']);

			if ($payment_module != null && strlen($payment_module) > 0)
			{
				include_once('includes/modules/payment/' . $payment_module . ".php");
				$class = $payment_module;
				$obj = new $class;
				if ($obj->enabled && $obj->confirm_zone($params, $this))
				{
					if ($action != 'ProcessPayment')
					{
						$setup = $obj->setup($params, $this);
						$rvalue{'Payment'}{0}{'module'}= $setup['code'];
						$rvalue{'Payment'}{0}{'payment_method'}= $setup['payment_method'];
						$rvalue{'Payment'}{0}{'check_cvv'}= $setup['check_cvv'];
						$rvalue{'Payment'}{0}{'accepted_credit_cards'}= $setup['accepted_credit_cards'];
						$thirdpp = (boolean)$setup['third_party_payment_process'];
                                                $rvalue{'Payment'}{0}{'third_party_payment_process'} = $thirdpp;
						if ($thirdpp) {
							$pass_cc = (boolean)$setup['pass_cc'];
							$rvalue{'Payment'}{0}{'pass_cc'} = $pass_cc;
							$rvalue{'Payment'}{0}{'third_party_payment_parameters'} = $setup['third_party_payment_parameters'];	
						}
					}
					else if ($action == 'ProcessPayment')
					{
						//Because its critical to get this right, default to error condition.
						//So you don't accidentally return a false positive.
						$this->errorCode = -1000;
						$this->warningCode = -1000;
						$this->errorMessage = 'ProcessPaymentUnknownError';
						$this->warningMessage = 'ProcessPaymentUnknownWarning';
						$this->pre_process($params);
						if ($this->errorCode != -1000) return;
						$process = $obj->process($params, $this);
						if ($this->errorCode != -1000)
						{
							$params['payment_module'] = '';
							$params['action'] = '';
							return $this->payment($params);
						}
						$params['order_status_id'] = $obj->status_id;
						if ($this->warningCode != -1000) {
							$params['order_status_id'] = 0;
						}

						$params['email_footer'] = $obj->email_footer;
						$orderId = $this->post_process($params);

						if ($this->errorCode == -1000) {
							$this->errorCode = 0;
							$this->errorMessage = '';
						}
						if ($this->warningCode == -1000) {
							$this->warningCode = 0;
							$this->warningMessage = '';
						}

						$setup = $obj->setup($params, $this);
						$rvalue{'Payment'}{0}{'module'}= $setup['code'];
						$rvalue{'Payment'}{0}{'payment_method'}= $setup['payment_method'];
						$rvalue{'Payment'}{0}{'check_cvv'}= $setup['check_cvv'];
						$rvalue{'Payment'}{0}{'accepted_credit_cards'}= $setup['accepted_credit_cards'];
						$thirdpp = (boolean)$setup['third_party_payment_process'];
                                                $rvalue{'Payment'}{0}{'third_party_payment_process'} = $thirdpp;
						if ($thirdpp) {
							$pass_cc = (boolean)$setup['pass_cc'];
							$rvalue{'Payment'}{0}{'pass_cc'} = $pass_cc;
							$rvalue{'Payment'}{0}{'third_party_payment_parameters'} = $setup['third_party_payment_parameters'];	
						}
						$rvalue{'Payment'}{0}{'orderId'} = $orderId;
					}
				}
			}
			else
			{
				$modules = explode(';', MODULE_PAYMENT_INSTALLED);
				reset($modules);
				$i = 0;					
				while (list(, $value) = each($modules)) 
				{
					include_once('includes/modules/payment/' . $value);
					$class = substr($value, 0, strrpos($value, '.'));
					$obj = new $class;
					if ($obj != null && $obj->enabled && $obj->confirm_zone($params, $this))
					{
						$setup = $obj->setup($params, $this);
						$rvalue{'Payment'}{$i}{'module'}= $setup['code'];
						$rvalue{'Payment'}{$i}{'payment_method'}= $setup['payment_method'];
						$rvalue{'Payment'}{$i}{'check_cvv'}= $setup['check_cvv'];
						$rvalue{'Payment'}{$i}{'accepted_credit_cards'}= $setup['accepted_credit_cards'];
						$thirdpp = (boolean)$setup['third_party_payment_process'];
                                                $rvalue{'Payment'}{$i}{'third_party_payment_process'} = $thirdpp;
						if ($thirdpp) {
							$pass_cc = (boolean)$setup['pass_cc'];
							$rvalue{'Payment'}{0}{'pass_cc'} = $pass_cc;
							$rvalue{'Payment'}{$i}{'third_party_payment_parameters'} = $setup['third_party_payment_parameters'];	
						}
						$i++;
					}
				}
			}
		}	

		$covalue{'CheckoutComponent'}{0}{'payment'} = $rvalue['Payment'];
		return $covalue;
	}

	/**
	 * Processing before payment module *
	 */

	function pre_process(&$params) 
	{
		$accountId = (int)$params['accountId'];
		$cc_number_length_min = (int)CC_NUMBER_MIN_LENGTH;
		$cc_owner_length_min = (int)CC_OWNER_MIN_LENGTH;

		if ($accountId < 1)
		{
			$entry_email_address_length_min = (int)ENTRY_EMAIL_ADDRESS_MIN_LENGTH;
			$entry_street_address_length_min = (int)ENTRY_STREET_ADDRESS_MIN_LENGTH;
			$entry_city_length_min = (int)ENTRY_CITY_MIN_LENGTH;

			$email_address = prepare_input($params['email_address']);
			if (strlen($email_address) < $entry_email_address_length_min || !validate_email_format($email_address)) {
				$this->errorCode = -50;
				$this->errorMessage = 'emailTooShort';
				return;
			}

			$shipToCompany = prepare_input($params['shipToCompany']);
			$shipToSuburb = prepare_input($params['shipToSuburb']);

			$shipToStreet = prepare_input($params['shipToStreet']);
			if (strlen($shipToStreet) < $entry_street_address_length_min) {
				$this->errorCode = -60;
				$this->errorMessage = 'shipToStreetAddressTooShort';
				return;
			}

			$shipToCity = prepare_input($params['shipToCity']);
			if (strlen($shipToCity) < $entry_city_address_length_min) {
				$this->errorCode = -70;
				$this->errorMessage = 'shipToCityTooShort';
				return;
			}

			$this->shipTo['company'] = $shipToCompany;
			$this->shipTo['street_address'] = $shipToStreet;
			$this->shipTo['suburb'] = $shipToSuburb;
			$this->shipTo['city'] = $shipToCity;

			$billToCompany = prepare_input($params['billToCompany']);
			$billToSuburb = prepare_input($params['billToSuburb']);

			$billToStreet = prepare_input($params['billToStreet']);
			if (strlen($billToStreet) < $entry_street_address_length_min) {
				$this->errorCode = -80;
				$this->errorMessage = 'billToStreetAddressTooShort';
				return;
			}

			$billToCity = prepare_input($params['billToCity']);
			if (strlen($billToCity) < $entry_city_address_length_min) {
				$this->errorCode = -90;
				$this->errorMessage = 'billToCityTooShort';
				return;
			}

			$this->billTo['company'] = $billToCompany;
			$this->billTo['street_address'] = $billToStreet;
			$this->billTo['suburb'] = $billToSuburb;
			$this->billTo['city'] = $billToCity;
			
			$this->accountInfo = $this->billTo;
			$this->accountInfo['email_address'] = $email_address;
		}

		$shipToName = prepare_input($params['shipToName']);
		if (strlen($shipToName) < $cc_owner_length_min) {
			$this->errorCode = -100;
			$this->errorMessage = 'shipToNameTooShort';
			return;
		}
		$this->shipTo['name'] = $shipToName;

		$billToName = prepare_input($params['billToName']);
		if (strlen($billToName) < $cc_owner_length_min) {
			$this->errorCode = -110;
			$this->errorMessage = 'billToNameTooShort';
			return;
		}
		$this->billTo['name'] = $billToName;

		$third_party_payment_process = (boolean)$params['third_party_payment_process'];
		$paymentMethod = prepare_input($params['paymentMethod']);
		if (!$third_party_payment_process && $paymentMethod == "credit")
		{
			$this->billTo['creditCardType'] = prepare_input($params['creditCardType']);
			$creditCardNumber = prepare_input($params['creditCardNumber']);
			if (strlen($creditCardNumber) < $cc_number_length_min) {
				$this->errorCode = -120;
				$this->errorMessage = 'creditCardTooShort';
				return;
			}
			$this->billTo['creditCardNumber'] = $creditCardNumber;
			$this->billTo['creditCardExpirationMonth'] = prepare_input($params['creditCardExpirationMonth']);
			$this->billTo['creditCardExpirationYear'] = prepare_input($params['creditCardExpirationYear']);
			$this->billTo['creditCardCVV'] = prepare_input($params['creditCardCVV']);
		}
		//TBD: Other paymentMethods may need setup here (echeck, etc.).
	}


	/**
	 * Processing after payment module *
	 */

	function post_process(&$params) 
	{
		$downloadEnabled = returnBoolean(DOWNLOAD_ENABLED);
		
		$shipping_module = prepare_input($params['shipping_module']);
		$shipping_service = prepare_input($params['shipping_service']);
		$payment_module = prepare_input($params['payment_module']);
		$payment_method = prepare_input($params['payment_method']);

		//Order
		$sql_data_array = array();
		$sql_data_array['customers_id'] = (int)$params['accountId'];
		$sql_data_array['customers_name'] = $this->accountInfo['name'];
		$sql_data_array['customers_company'] = $this->accountInfo['company'];
		$sql_data_array['customers_street_address'] = $this->accountInfo['street_address'];
		$sql_data_array['customers_suburb'] = $this->accountInfo['suburb'];
		$sql_data_array['customers_city'] = $this->accountInfo['city'];
		$sql_data_array['customers_postcode'] = $this->accountInfo['postcode'];
		$sql_data_array['customers_state'] = $this->accountInfo['state'];
		$sql_data_array['customers_country'] = $this->accountInfo['country'];
		$sql_data_array['customers_telephone'] = $this->accountInfo['telephone'];
		$sql_data_array['customers_email_address'] = $this->accountInfo['email_address'];
		$sql_data_array['customers_address_format_id'] = (int)$this->accountInfo['address_format_id'];
		$sql_data_array['delivery_name'] = $this->shipTo['name'];
		$sql_data_array['delivery_company'] = $this->shipTo['company'];
		$sql_data_array['delivery_street_address'] = $this->shipTo['street_address'];
		$sql_data_array['delivery_suburb'] = $this->shipTo['suburb'];
		$sql_data_array['delivery_city'] = $this->shipTo['city'];
		$sql_data_array['delivery_postcode'] = $this->shipTo['postcode'];
		$sql_data_array['delivery_state'] = $this->shipTo['state'];
		$sql_data_array['delivery_country'] = $this->shipTo['country'];
		$sql_data_array['delivery_address_format_id'] = (int)$this->shipTo['address_format_id'];
		$sql_data_array['billing_name'] = $this->billTo['name'];
		$sql_data_array['billing_company'] = $this->billTo['company'];
		$sql_data_array['billing_street_address'] = $this->billTo['street_address'];
		$sql_data_array['billing_suburb'] = $this->billTo['suburb'];
		$sql_data_array['billing_city'] = $this->billTo['city'];
		$sql_data_array['billing_postcode'] = $this->billTo['postcode'];
		$sql_data_array['billing_state'] = $this->billTo['state'];
		$sql_data_array['billing_country'] = $this->billTo['country'];
		$sql_data_array['billing_address_format_id'] = (int)$this->billTo['address_format_id'];
		$sql_data_array['payment_method'] = $payment_module . "_" . $payment_method;
		$sql_data_array['shipping_module'] = $shipping_module . "_" . $shipping_service;
		$sql_data_array['currency'] = $this->currency['code'];
		$sql_data_array['currency_value'] = $this->currency['value'];
		$sql_data_array['orders_status'] = (int)$params['order_status_id'];
		$sql_data_array['last_modified'] = 'now()';
		$sql_data_array['date_purchased'] = 'now()';
		db_perform(TABLE_ORDERS, $sql_data_array, 'insert');
		$orderId = mysql_insert_id();

		//Orders Product && Orders Products Attributes
		$cart = &$this->cart;
		$sz = sizeof($cart);
		for ($i=0; $i< $sz; $i++)
		{
			$productId = (int)$cart[$i]['id'];
			$productName = $cart[$i]['name'];
			$productModel = $cart[$i]['model'];
			$price = (double)$cart[$i]['cart_price'];
			$quantity = (int)$cart[$i]['cart_qty'];
			$inventory_qty = (int)$cart[$i]['inventory_qty'];
			$sql_data_array = array();
			$sql_data_array['orders_id'] = $orderId;
			$sql_data_array['products_id'] = $productId;
			$sql_data_array['products_model'] = $productModel;
			$sql_data_array['products_name'] = $productName;
			$sql_data_array['products_price'] = (double)$cart[$i]['products_price'];
			$sql_data_array['final_price'] = $price;
			$sql_data_array['products_tax'] = (double)$cart[$i]['tax_rate'];
			$sql_data_array['products_quantity'] = (int)$cart[$i]['cart_qty'];
			$sql_data_array['products_weight'] = (double) $cart[$i]['weight'];
			$sql_data_array['products_tax_class_id'] = (int)$cart[$i]['tax_class_id'];
			db_perform(TABLE_ORDERS_PRODUCTS, $sql_data_array, 'insert');
			$orderProductId = mysql_insert_id();

			//Update Product Orderered and Inventory.
			$sql = 'update ' . TABLE_PRODUCTS . ' set products_ordered  = products_ordered + '. $quantity .' where products_id = \'' . $productId . '\'';
			mysql_query($sql) or die(mysql_error());
			if (returnBoolean(STOCK_LIMITED))
			{
				$sql = 'update ' . TABLE_PRODUCTS . ' set products_quantity  = products_quantity - '. $quantity .' where products_id = \'' . $productId . '\'';
				mysql_query($sql) or die(mysql_error());
			}
			if (($inventory_qty - $quantity) < (int)STOCK_REORDER_LEVEL)
			{
				//TBD Send Email to Owner of Stock
			}

			$attributes = &$cart[$i]['cart_options'];
			$sz1 = sizeof($attributes);
    			$products_ordered_attributes = '';
			for ($j=0; $j<$sz1; $j++)
			{
				$attributeName = $attributes[$j]['name'];
				$attributeValue = $attributes[$j]['values_name'];
				$sql_data_array_attributes = array();
				$sql_data_array_attributes['orders_id'] = $orderId;
				$sql_data_array_attributes['orders_products_id'] = $orderProductId;
				$sql_data_array_attributes['products_options'] = $attributeName;
				$sql_data_array_attributes['products_options_values'] = $attributeValue;
				$sql_data_array_attributes['options_values_price'] = $attributes[$j]['values_price'];
				$sql_data_array_attributes['price_prefix'] = $attributes[$j]['values_price_prefix'];
				db_perform(TABLE_ORDERS_PRODUCTS_ATTRIBUTES, $sql_data_array_attributes, 'insert');
        			$products_ordered_attributes .= "\n\t" . $attributeName . ' ' . $attributeValue;
        			
        			//downloads?
        			if ($downloadEnabled) {
        				$filename = $attributes[$j]['filename'];
        				if ($filename != null && strlen($filename) > 0) {
        					$sql_data_array_attributes_download = array();
						$sql_data_array_attributes_download['orders_id'] = $orderId;
						$sql_data_array_attributes_download['orders_products_id'] = $orderProductId;
						$sql_data_array_attributes_download['orders_products_filename'] = $filename;
						$maxdays = $attributes[$j]['maxdays'];
						$sql_data_array_attributes_download['download_maxdays'] = $maxdays;
						$sql_data_array_attributes_download['download_count'] = $attributes[$j]['maxcount'];
						db_perform(TABLE_ORDERS_PRODUCTS_DOWNLOAD, $sql_data_array_attributes_download, 'insert'); 
        					$products_ordered_attributes .= ' please download within ' . $maxdays . ' days';
        				}
        			}
			}

			$total_price = $price * $quantity;
			$products_ordered .= $quantity . ' x ' . $productName . ' (' . $productModel . ') = ' . $this->currency_format($total_price) . $products_ordered_attributes . "\n";
		}

		//Orders Status History
		$sql_data_array = array();
		$sql_data_array['orders_id'] = $orderId;
		$sql_data_array['orders_status_id'] = (int)$params['order_status_id'];
		$sql_data_array['date_added'] = 'now()';
		$sql_data_array['customer_notified'] = 0;
		$comment= prepare_input($params['checkoutComment']);
		if ($this->warningCode != -1000) $comment .= ' ' . $this->warningMessage;
		$sql_data_array['comments'] = $comment;
		db_perform(TABLE_ORDERS_STATUS_HISTORY, $sql_data_array, 'insert');

		//Orders Total
		$cart_prices = &$this->cart_prices;
		reset($cart_prices);
		$i = 0;
		$total_price = 0.0;
		while (list(,$price) = each($cart_prices))
		{
			$total_class = $price['class'];
			if ($total_class == 'ot_total') $total_price = (double)$price['value'];

			$sql_data_array = array();
			$sql_data_array['orders_id'] = $orderId;
			$sql_data_array['title'] = $price['title'];
			$sql_data_array['text'] = (string)$price['value'];
			$sql_data_array['value'] = $price['value'];
			$sql_data_array['class'] = $total_class;
			$sql_data_array['sort_order'] = $i;
			db_perform(TABLE_ORDERS_TOTAL, $sql_data_array, 'insert');
			$i++;
		}

		//Orders Payment
		$downloads_flag = 0;
		$sqlQuery = 'select downloads_flag from ' . TABLE_ORDERS_STATUS . ' where orders_status_id=' . (int)$params['order_status_id'];
		$dataReturned = mysql_query($sqlQuery) or die(mysql_error());
		while($row = mysql_fetch_array($dataReturned))
		{
			$downloads_flag = (int)$row['downloads_flag'];
			break;
		}

		//Can't download means order is not payed for yet.
		if ($downloads_flag == 0) $total_price = 0.0;
		
		$sql_data_array = array();
		$sql_data_array['orders_id'] = $orderId;
		$sql_data_array['payment_amount'] = $total_price;
		$sql_data_array['payment_timestamp'] = 'now()';
		$sql_data_array['comments'] = $payment_module . "_" . $payment_method;
		db_perform(TABLE_ORDERS_PAYMENTS, $sql_data_array, 'insert');

		// clear cart
		$basketAccountId = $params['basketAccountId'];
		$sql = 'delete from ' . TABLE_CUSTOMERS_BASKET . ' where customers_id = ' . $basketAccountId;
		mysql_query($sql) or die(mysql_error());
		$sql = 'delete from ' . TABLE_CUSTOMERS_BASKET_ATTRIBUTES . ' where customers_id = ' . $basketAccountId;
		mysql_query($sql) or die(mysql_error());
		// email confirmation
		$isLogin = (boolean)$this->accountInfo['isLogin'];
  		$email_order = CO_EMAIL_TEXT_THANKYOU . "\n" . EMAIL_SEPARATOR . "\n" . CO_EMAIL_TEXT_ORDER_NUMBER . ' ' . $orderId . "\n";
		if ($isLogin) $email_order .= sprintf(CO_EMAIL_TEXT_INVOICE_URL, HTTPS_SERVER . '#OrderComponent--' . $orderId) . "\n";
                $email_order .= CO_EMAIL_TEXT_DATE_ORDERED . ' ' . strftime(DATE_FORMAT_LONG) . "\n\n";

		if ($params['checkoutComment']) {
			$email_order .= prepare_input($params['checkoutComment']) . "\n\n";
		}

		$email_order .= CO_EMAIL_TEXT_PRODUCTS . "\n" . 
			EMAIL_SEPARATOR . "\n" . 
			$products_ordered . 
			EMAIL_SEPARATOR . "\n";

		$cart_prices = &$this->cart_prices;
		reset($cart_prices);
		foreach ($cart_prices as $key => $cart_price)
    		{
			$email_order .= $cart_price['title'] . ' ' . $this->currency_format($cart_price['value']) . "\n";
		}

		$email_order .= "\n" . CO_EMAIL_TEXT_DELIVERY_ADDRESS . "\n" . 
			EMAIL_SEPARATOR . "\n" .
			address_label($this->shipTo) . "\n";

		$email_order .= "\n" . CO_EMAIL_TEXT_BILLING_ADDRESS . "\n" .
			EMAIL_SEPARATOR . "\n" .
			address_label($this->billTo) . "\n";

		$email_order .= "\n" . CO_EMAIL_TEXT_PAYMENT_METHOD . "\n" . 
			EMAIL_SEPARATOR . "\n";
		$email_order .= $payment_module . "\n\n";

		if ($params['email_footer']) { 
			$email_order .= $params['email_footer'] . "\n\n";
		}
 
		send_email($this->accountInfo['name'], $this->accountInfo['email_address'], CO_EMAIL_TEXT_SUBJECT, $email_order, STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS);

		// send emails to other people
  		if (SEND_EXTRA_ORDER_EMAILS_TO != '') {
			send_email('', SEND_EXTRA_ORDER_EMAILS_TO, CO_EMAIL_TEXT_SUBJECT, $email_order, STORE_OWNER, STORE_OWNER_EMAIL_ADDRESS);
		}

		clean_cache('AlsoPurchasedComponent');
		clean_cache('BestSellersComponent');

		return $orderId;
	}


	function currency_format($number)
	{
		$currency = &$this->currency;
		return  $currency['symbol_left'] . 
			number_format($number * $currency['value'], $currency['decimal_places'], $currency['decimal_point'], $currency['thousands_point']) . 
			$currency['symbol_right'];
	}
}
?>
